//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Workflow.ComponentModel;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System.Reflection;
    using System.Xml;
    using Microsoft.Research.ScientificWorkflow.TridentComposer;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.Activities;
    using SR = Microsoft.Research.DataLayer;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities.Properties;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Globalization;

    /// <summary>
    /// Interaction logic for ConditionConnector.xaml
    /// </summary>
    [System.Runtime.InteropServices.GuidAttribute("08A787D7-9D8B-4568-B533-E3CDCD48A86A")]
    public partial class ConditionConnector : UserControl, ITridentUIElement
    {
        public event EventHandler ShowProperties;
        public event EventHandler InsertIntoSubsection;
        private ComposerControl composerCtrl;
        private const double activityBodyHeight = 40.0;
        private const double activityBodyWidth = 50.0;
        private CompositeActivityModel conditionActivity;
        private ConditionDataStore dictionary;
        private static Dictionary<String, DataTypeModel> dataTypes;
        private WellFormedConditionalTreeInfo treeInfo;
        private ConditionParameter conditionalOutput;
        private bool logicalOperatordragStart;
        private ObservableCollection<ITridentUIElement> conditionChildren = new ObservableCollection<ITridentUIElement>();

        /// <summary>
        /// Constructor Intialises the condition connector
        /// </summary>
        /// <param name="compActivity">ActivityModel</param>
        /// <param name="datatypes">Dictionary<String, DataTypeModel></param>
        public ConditionConnector(CompositeActivityModel compActivity, Dictionary<String, DataTypeModel> dataTypes)
        {
            InitializeComponent();
            this.conditionActivity = compActivity;
            ConditionConnector.dataTypes = dataTypes;
            this.dropCircle.Name = "Conditional_DropCircle_" + compActivity.UniqueId;
            this.Name = "ConditionalConnector_" + compActivity.UniqueId;
            this.dropCircle.circle.Stroke = (new BrushConverter()).ConvertFromString("#FF94B3C4") as Brush;
            this.Loaded += new RoutedEventHandler(this.OnLoaded);
            this.Unloaded += new RoutedEventHandler(this.OnUnload);
            this.SelectElement += new EventHandler(OnSelectElement);
            this.DeleteElement += new EventHandler(OnDeleteElement);
            this.ShowProperties += new EventHandler(this.OnShowProperties);
            this.InsertIntoSubsection += new EventHandler(this.OnInsertIntoSubsection);
            this.ProvenanceMenuClick += new EventHandler<ProvenanceModeEventArgs>(ConditionConnector_ProvenanceMenuClick);
            this.conditionChildren.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ConditionChildrenChanged);
            this.UpdateClick += delegate(object sender, ModelEventArgs args) { };
        }

        void ConditionConnector_ProvenanceMenuClick(object sender, ProvenanceModeEventArgs e)
        {
            // Note: dummy implementation to avoid warning
        }

        private void OnInsertIntoSubsection(object sender, EventArgs e)
        {
            // Note: dummy implementation to avoid warning
        }

        private void ConditionChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (ITridentUIElement elem in e.OldItems)
                {
                    this.operatorCanvas.Children.Remove(elem as UIElement);
                }
            }
        }

        private void OnDeleteElement(object sender, EventArgs e)
        {
            // Note: dummy implementation to avoid warning
        }

        private void OnSelectElement(object sender, EventArgs e)
        {
            // Note: dummy implementation to avoid warning
        }

        /// <summary>
        /// The event handler for the loaded event.
        /// </summary>
        /// <param name="sender">Source</param>
        /// <param name="e">event args.</param>
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.GetComposerControl();
            this.dictionary = this.composerCtrl.ConditionStore;
            this.AddBranchParameters();
            this.AddInteractionHandlers();

            // Open from registry condition.
            if (this.dictionary != null && ((Collection<LogicalOperatorActivityBody>)this.dictionary.GetConditionList(this.conditionActivity.UniqueId)).Count == 0)
            {
                if (conditionActivity.Children.Count > 0)
                {
                    this.CreateLogicalOperatorBody();
                }

                SimpleActivityModel lastModel = this.GetConditionOutput();

                if (lastModel != null)
                {
                    WellFormedConditionalTreeInfo treeInfo = this.CreateTreeInfo(lastModel, null, -1);
                    if (this.CheckIfWellFormedTree(lastModel, treeInfo, new List<SimpleActivityModel>(), -1))
                    {
                        int level = -1;
                        double startpoint = 0.0;
                        this.BuildWellFormedTreeOnCanvas(treeInfo, ref level, ref startpoint);
                    }
                }

                this.conditionActivity.IsCollapsed = false;
                this.LoadDropedConditions();
                this.AddConditionActivityParameter();
                this.RepositionEndConnector();
                this.UpdateLayout();
                this.composerCtrl.RefreshUI();
            }
        }

        /// <summary>
        /// The event handler for the loaded event.
        /// </summary>
        /// <param name="sender">Source</param>
        /// <param name="e">event args.</param>
        private void OnUnload(object sender, RoutedEventArgs e)
        {
            this.RemoveInteractionHandlers();
        }

        /// <summary>
        /// Add the interaction handlers according to the mode.
        /// </summary>
        private void AddInteractionHandlers()
        {
            if (this.composerCtrl != null && this.composerCtrl.CurrentRenderMode == RenderMode.ComposerMode)
            {
                this.operatorCanvas.Drop += new DragEventHandler(operatorCanvas_Drop);
                this.operatorCanvas.DragOver += new DragEventHandler(operatorCanvas_DragOver);
                this.dropCircle.AllowDrop = true;
            }
            else
            {
                this.dropCircle.AllowDrop = false;
            }
        }

        /// <summary>
        /// Remove the interaction handlers according to the mode.
        /// </summary>
        private void RemoveInteractionHandlers()
        {
            if (this.composerCtrl != null && this.composerCtrl.CurrentRenderMode == RenderMode.ComposerMode)
            {
                this.operatorCanvas.Drop -= new DragEventHandler(operatorCanvas_Drop);
                this.operatorCanvas.DragOver -= new DragEventHandler(operatorCanvas_DragOver);
            }
        }

        #region Properties

        /// <summary>
        /// Checks all operators are in the well formed tree
        /// </summary>
        /// <returns>List<ActivityModel></returns>
        public Collection<SimpleActivityModel> CheckForOrphanElements()
        {
            Collection<SimpleActivityModel> orphanModels = new Collection<SimpleActivityModel>();
            if (treeInfo != null)
            {
                foreach (BaseModel model in this.conditionActivity.Children)
                {
                    SimpleActivityModel simpleModel = model as SimpleActivityModel;
                    if (simpleModel != null && !WellFormedConditionalTreeInfo.ActivityModelExistsInTree(treeInfo, simpleModel))
                    {
                        orphanModels.Add(simpleModel);
                    }
                }
            }

            return orphanModels;
        }

        /// <summary>
        /// checks well formed tree exits or not
        /// </summary>
        public bool WellFormedTreeExists
        {
            get
            {
                SimpleActivityModel finalResult = this.GetConditionOutput();
                if (null != finalResult)
                {
                    WellFormedConditionalTreeInfo info = this.CreateTreeInfo(finalResult, null, -1);

                    if (this.CheckIfWellFormedTree(finalResult, info, new List<SimpleActivityModel>(), -1))
                    {
                        this.treeInfo = info;
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Gets the Conditional Activity model
        /// </summary>
        public CompositeActivityModel ConditionActivity
        {
            get { return conditionActivity; }
        }

        #endregion

        public bool OnSave(Collection<SimpleActivityModel> orphanModelList)
        {
            if (!WellFormedTreeExists)
            {
                return false;
            }
            else
            {
                this.conditionActivity.Children.Clear();

                // Remove the orphans from the UI.
                foreach (SimpleActivityModel orphanModel in orphanModelList)
                {
                    LogicalOperatorActivityBody activityBody = this.dictionary.GetActivityBody(this.conditionActivity.UniqueId, orphanModel);
                    if (activityBody != null)
                    {
                        Panel parent = activityBody.Parent as Panel;
                        if (parent != null)
                        {
                            parent.Children.Remove(activityBody);
                            this.dictionary.RemoveLogicalOperator(this.conditionActivity.UniqueId, activityBody);
                        }
                    }
                }

                // Build a well formed tree onsave.
                SimpleActivityModel lastModel = this.GetConditionOutput();

                if (lastModel != null)
                {
                    WellFormedConditionalTreeInfo infoForTree = this.CreateTreeInfo(lastModel, null, -1);
                    if (this.CheckIfWellFormedTree(lastModel, infoForTree, new List<SimpleActivityModel>(), -1))
                    {
                        int level = -1;
                        double startpoint = 0.0;
                        this.BuildWellFormedTreeOnCanvas(infoForTree, ref level, ref startpoint);
                        this.operatorCanvas.UpdateLayout();
                        this.RepositionEndConnector();
                    }
                }

                if (this.treeInfo != null)
                {
                    AddActivityToModel(this.treeInfo);
                }
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentInfo"></param>
        private void AddActivityToModel(WellFormedConditionalTreeInfo parentInfo)
        {
            if (parentInfo.Children != null && parentInfo.Children.Count > 0)
            {
                foreach (WellFormedConditionalTreeInfo childInfo in parentInfo.Children)
                {
                    AddActivityToModel(childInfo);
                }
            }
            if (!this.conditionActivity.Children.Contains(parentInfo.CurrentModel))
            {
                this.conditionActivity.Children.Add(parentInfo.CurrentModel);
            }
        }

        private void RepositionEndConnector()
        {
            if (null != this.conditionalOutput)
            {
                this.operatorCanvas.UpdateLayout();
                Canvas.SetLeft(this.conditionalOutput, this.operatorCanvas.Width);
                Canvas.SetTop(this.conditionalOutput, this.operatorCanvas.Height / 2 - 10);
                this.operatorCanvas.UpdateLayout();
                this.composerCtrl.RepositionLines();
            }
        }

        private void CreateLogicalOperatorBody()
        {
            foreach (BaseModel model in this.conditionActivity.Children)
            {
                SimpleActivityModel simpleModel = model as SimpleActivityModel;
                if (simpleModel != null)
                {
                    LogicalOperatorActivityBody logicalOpearator = this.DesignConditionalOperator(simpleModel, true);
                    this.dictionary.AddConditionOperator(this.conditionActivity.UniqueId, logicalOpearator);
                    foreach (string key in logicalOpearator.InputParameterElements.Keys)
                    {
                        string globalKey = model.UniqueId + "." + key;
                        this.composerCtrl.InputParameterElements[globalKey] = logicalOpearator.InputParameterElements[key];
                    }

                    foreach (string key in logicalOpearator.OutputParameterElements.Keys)
                    {
                        string globalKey = model.UniqueId + "." + key;
                        this.composerCtrl.OutputParameterElements[globalKey] = logicalOpearator.OutputParameterElements[key];
                    }
                }
            }
        }

        /// Adds the parameters to composer control dictionary
        /// </summary>
        private void AddBranchParameters()
        {
            CompositeActivityModel trueBranch = ((this.conditionActivity.ParentModel.Children[1] as CompositeActivityModel).Children[0] as CompositeActivityModel).Children[0] as CompositeActivityModel;
            CompositeActivityModel falseBranch = ((this.conditionActivity.ParentModel.Children[1] as CompositeActivityModel).Children[1] as CompositeActivityModel).Children[0] as CompositeActivityModel;

            foreach (ParameterDescriptionModel trueParam in trueBranch.InputParameters)
            {
                string globalKey = trueBranch.UniqueId + "." + trueParam.PropertyName;
                this.composerCtrl.InputParameterElements[globalKey] = null;
            }
            foreach (ParameterDescriptionModel falseParam in falseBranch.InputParameters)
            {
                string globalKey = falseBranch.UniqueId + "." + falseParam.PropertyName;
                this.composerCtrl.InputParameterElements[globalKey] = null;
            }
        }

        /// <summary>
        /// Adds the conditional activity parameters
        /// </summary>
        public void AddConditionActivityParameter()
        {
            if (this.composerCtrl != null)
            {
                ParameterDescriptionModel param = this.conditionActivity.InputParameters[0];
                ConditionParameter inputparameter = new ConditionParameter(param, ParameterFlowType.InputParameter, this.conditionActivity);
                inputparameter.Name = this.ConditionActivity.UniqueId + "_" + param.Name;
                Dictionary<string, object> dataHolder = new Dictionary<string, object>(2);
                dataHolder.Add("ParameterDescriptionModel", this.conditionActivity.InputParameters[0]);
                dataHolder.Add("ActivityModel", this.conditionActivity);
                inputparameter.DataContext = dataHolder;

                this.composerCtrl.InputParameterElements[this.conditionActivity.UniqueId + "." + param.PropertyName] = inputparameter;
                Canvas.SetLeft(inputparameter, this.operatorCanvas.Width);
                Canvas.SetTop(inputparameter, this.operatorCanvas.Height / 2 - 10);
                this.operatorCanvas.Children.Add(inputparameter);
                this.conditionalOutput = inputparameter;
            }
        }

        internal ObservableCollection<ITridentUIElement> ConditionChildren
        {
            get { return this.conditionChildren; }
        }

        /// <summary>
        /// Bind the Condition activity Output to True and false branch parameters
        /// </summary>
        private void BindBranchActivities()
        {
            if (null != (this.conditionActivity.ParentModel.Children[1] as CompositeActivityModel).Children[0])
            {
                CompositeActivityModel trueBranch = ((this.conditionActivity.ParentModel.Children[1] as CompositeActivityModel).Children[0] as CompositeActivityModel).Children[0] as CompositeActivityModel;
                CompositeActivityModel falseBranch = ((this.conditionActivity.ParentModel.Children[1] as CompositeActivityModel).Children[1] as CompositeActivityModel).Children[0] as CompositeActivityModel;
                trueBranch.InputParameters[0].CreateBindings(this.conditionActivity.UniqueId, this.conditionActivity.InputParameters[0].PropertyName); trueBranch.InputParameters[0].IsDatabound = true;
                falseBranch.InputParameters[0].CreateBindings(this.conditionActivity.UniqueId, this.conditionActivity.InputParameters[0].PropertyName); trueBranch.InputParameters[0].IsDatabound = true;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void LoadDropedConditions()
        {
            Collection<LogicalOperatorActivityBody> conditionStore = this.dictionary.GetConditionList(this.conditionActivity.UniqueId);
            if (null != conditionStore)
            {
                this.operatorCanvas.Children.Clear();
                conditionStore = this.dictionary.GetConditionList(this.conditionActivity.UniqueId);
                for (int dropCounter = 0; dropCounter < conditionStore.Count; dropCounter++)
                {
                    this.AddLogicalOperatorToCanvas(conditionStore[dropCounter]);
                }
            }
        }

        /// <summary>
        /// Adds the Logical Operator to the Operator canvas area
        /// </summary>
        /// <param name="logicalOperator"></param>
        private void AddLogicalOperatorToCanvas(LogicalOperatorActivityBody logicalOperator)
        {
            // Remove the child from the operatorCanvas
            if (null != logicalOperator.Parent)
            {
                ((Canvas)logicalOperator.Parent).Children.Remove(logicalOperator);
            }
            this.operatorCanvas.Children.Add(logicalOperator);
            this.composerCtrl.UIElements[logicalOperator.Model.UniqueId] = logicalOperator;
            this.conditionChildren.Add(logicalOperator);
            Canvas.SetLeft(logicalOperator, logicalOperator.Left);

            if (logicalOperator.Top + activityBodyHeight >= this.operatorCanvas.Height)
            {
                this.IncreaseCanvasHeight();
            }

            logicalOperator.Model.IsCollapsed = false;


            Canvas.SetTop(logicalOperator, logicalOperator.Top);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private SimpleActivityModel GetConditionOutput()
        {
            SimpleActivityModel sourceModel = null;

            if (this.conditionActivity.InputParameters.Count > 0)
            {
                ParameterDescriptionModel inputParam = this.conditionActivity.InputParameters[0];
                if (inputParam != null)
                {
                    if (!inputParam.IsDatabound)
                    {
                        return sourceModel;
                    }
                    else
                    {
                        if (inputParam.Value != null)
                        {
                            DatabindModel bind = inputParam.Value as DatabindModel;
                            string sourceActivityName = bind.SourceActivityName;
                            sourceModel = this.dictionary.GetActivityModel(this.conditionActivity.UniqueId, sourceActivityName);
                        }
                    }
                }
            }

            return sourceModel;
        }

        /// <summary>
        /// Increases the Operator canvas height
        /// </summary>
        private void IncreaseCanvasHeight()
        {
            this.operatorCanvas.Height = this.operatorCanvas.Height + 50;
        }

        /// <summary>
        /// Event Handler for Drop Canvas
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">DragEventArgs</param>
        private void OnDropAreaDrop(object sender, DragEventArgs e)
        {
            ActivityMetadata metadata = (ActivityMetadata)e.Data.GetData(typeof(ActivityMetadata));

            // Create a activity model out of the activity meta.
            SimpleActivityModel model = null;
            if (metadata != null)
            {
                model = new SimpleActivityModel(metadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.InvariantCulture));
                if (null != model)
                {
                    // drop is allowed for conditional activities. GetConditionalActivity retrives all supporting activities for condition
                    if (model.IsConditionActivity)
                    {
                        LogicalOperatorActivityBody logicalOpearator = this.DesignConditionalOperator(model, true);
                        this.IncreaseCanvasHeight();
                        logicalOpearator.Left = (this.operatorCanvas.Width - logicalOpearator.Width) / 2;
                        logicalOpearator.Top = this.operatorCanvas.Height - logicalOpearator.Height;
                        this.operatorCanvas.Children.Add(logicalOpearator);
                        this.conditionChildren.Add(logicalOpearator);

                        if (null != this.conditionActivity)
                        {
                            this.dictionary.AddConditionOperator(this.conditionActivity.UniqueId, logicalOpearator);
                        }

                        foreach (string key in logicalOpearator.InputParameterElements.Keys)
                        {
                            string globalKey = model.UniqueId + "." + key;
                            this.composerCtrl.InputParameterElements[globalKey] = logicalOpearator.InputParameterElements[key];
                        }

                        foreach (string key in logicalOpearator.OutputParameterElements.Keys)
                        {
                            string globalKey = model.UniqueId + "." + key;
                            this.composerCtrl.OutputParameterElements[globalKey] = logicalOpearator.OutputParameterElements[key];
                        }

                        this.conditionActivity.Children.Add(model);
                        model.ParentModel = this.conditionActivity;
                        this.composerCtrl.IsWFCommitted = false;
                        this.composerCtrl.UIElements[model.UniqueId] = logicalOpearator;
                        this.composerCtrl.UpdateLayout();
                        this.composerCtrl.RepositionLines();
                        this.composerCtrl.CurrentComposerRenderHelper.UpdateDataTypes(model);
                    }
                    else
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(model.Name + ScientificWorkFlow.ConditionZoneInvalidActivity);
                    }
                }
            }
        }

        /// <summary>
        /// Whenever a drag over is reported on this drop-able area.
        /// </summary>
        /// <param name="sender">
        /// Drop-able area.
        /// </param>
        /// <param name="e">
        /// Attributes of the event.
        /// </param>
        private void OnDropAreaDragOver(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.All;
        }

        #region Drag Drop for Canvas

        private void operatorCanvas_Drop(object sender, DragEventArgs e)
        {
            if (this.logicalOperatordragStart == false)
            {
                return;
            }
            ConditionParamControl source = (((e.OriginalSource) as FrameworkElement).Parent) as ConditionParamControl;
            if (source != null)
            {
                SimpleActivityModel finalResult = this.GetConditionOutput();
                if (null != finalResult)
                {
                    this.BindBranchActivities();
                    WellFormedConditionalTreeInfo info = this.CreateTreeInfo(finalResult, null, -1);
                    if (this.CheckIfWellFormedTree(finalResult, info, new List<SimpleActivityModel>(), -1))
                    {
                        this.treeInfo = info;
                        int level = -1;
                        double startpoint = 0.0;
                        BuildWellFormedTreeOnCanvas(info, ref level, ref startpoint);
                        this.operatorCanvas.UpdateLayout();
                        this.composerCtrl.RepositionLines();
                        this.composerCtrl.IsWFCommitted = false;
                        this.RepositionEndConnector();
                    }
                }
            }
            else
            {
                LogicalOperatorActivityBody cond = (LogicalOperatorActivityBody)e.Data.GetData(typeof(LogicalOperatorActivityBody));
                if (null != cond)
                {
                    Point dropPosition = e.GetPosition(this.operatorCanvas);
                    double leftPosition = (dropPosition.X + cond.Width) > this.operatorCanvas.Width ? this.operatorCanvas.Width - cond.Width : dropPosition.X;
                    double topPosition = (dropPosition.Y + cond.Height) > this.operatorCanvas.Height ? this.operatorCanvas.Height - cond.Height : dropPosition.Y;
                    cond.Left = leftPosition;
                    cond.Top = topPosition;
                    this.UpdateLayout();
                    this.composerCtrl.RepositionLines();
                    this.GetConditionOutput();
                }
            }
        }

        /// <summary>
        /// Event Handlers for conditionalOpearator Preview MouseLeftButtonDown
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">MouseButtonEventArgs</param>
        private void conditionalOpearator_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.OriginalSource is System.Windows.Shapes.Ellipse)
            {
                return;
            }

            // Do drag if the selected object is activity Body
            LogicalOperatorActivityBody activityBody = sender as LogicalOperatorActivityBody;
            if (activityBody == null)
            {
                return;
            }

            if (((SimpleActivityModel)activityBody.DataContext).ActivityClass.Equals("TridentBasicActivities.Activities.IfCondition"))
            {
                return;
            }

            this.logicalOperatordragStart = false;
            DragDrop.DoDragDrop((System.Windows.DependencyObject)e.Source, activityBody, DragDropEffects.Copy);
        }

        /// <summary>
        /// Event handler for Operator Canvas drag Over
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">DragEventArgs</param>
        private void operatorCanvas_DragOver(object sender, DragEventArgs e)
        {
            // Set the drag effect as none. If the dragged object is not a LogicalOperatorActivityBody and  not a ParameterDragInfo
            LogicalOperatorActivityBody cond = (LogicalOperatorActivityBody)e.Data.GetData(typeof(LogicalOperatorActivityBody));
            ParameterDragInfo dragInfo = (ParameterDragInfo)e.Data.GetData(typeof(ParameterDragInfo));
            if (cond == null && dragInfo == null)
            {
                e.Effects = DragDropEffects.None;
            }

            this.logicalOperatordragStart = true;
        }

        #endregion

        /// <summary>
        /// Designs the LogicalOperatorActivityBody for Conditional Operator
        /// </summary>
        /// <param name="model">ActivityModel</param>
        /// <param name="isDeleteable">bool</param>
        /// <returns>LogicalOperatorActivityBody</returns>
        private LogicalOperatorActivityBody DesignConditionalOperator(SimpleActivityModel model, bool isDeleteable)
        {
            LogicalOperatorActivityBody logicalOperator = new LogicalOperatorActivityBody(model, dataTypes);
            logicalOperator.ShowProperties += new EventHandler(this.OnShowProperties);
            logicalOperator.HorizontalAlignment = HorizontalAlignment.Stretch;
            logicalOperator.DataContext = model;
            logicalOperator.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(conditionalOpearator_PreviewMouseLeftButtonDown);
            if (isDeleteable)
            {
                logicalOperator.DeleteElement += new EventHandler(this.OnDeleteActivity);
            }

            // ProvenanceMenuClick Evenhandler is set when the mode is provenance mode.
            if (this.composerCtrl.CurrentRenderMode == RenderMode.ProvenanceMode)
            {
                logicalOperator.ProvenanceMenuClick += new EventHandler<ProvenanceModeEventArgs>(OnProvenanceMenuClick);
            }

            return logicalOperator;
        }

        /// <summary>
        /// Called when provenance menu item is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.UIDesigner.ProvenanceModeEventArgs"/> instance containing the event data.</param>
        void OnProvenanceMenuClick(object sender, ProvenanceModeEventArgs e)
        {
            this.composerCtrl.OnProvenanceMenuClick(sender, e);
        }

        /// <summary>
        /// Delete the activity.
        /// </summary>
        /// <param name="sender">
        /// Activity to be deleted.
        /// </param>
        /// <param name="e">
        /// DeleteElementEventArgs.
        /// </param>
        private void OnDeleteActivity(object sender, EventArgs e)
        {
            this.composerCtrl.DeleteActivity();
        }

        /// <summary>
        /// Event handler for displaying property Pane
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">EventArgs</param>
        private void OnShowProperties(object sender, EventArgs e)
        {
            this.composerCtrl.ShowProperties();
        }

        /// <summary>
        /// Build the well formed tree
        /// </summary>
        /// <param name="rootTreeInfo">WellFormedConditionalTreeInfo</param>
        /// <param name="maxLevel">int</param>
        /// <param name="lastUsedYCoordinate">double</param>
        private void BuildWellFormedTreeOnCanvas(WellFormedConditionalTreeInfo rootTreeInfo, ref int maxLevel, ref double lastUsedYCoordinate)
        {
            int level = Math.Abs(rootTreeInfo.Level);
            if (level > maxLevel)
            {
                maxLevel = level;
            }
            if (rootTreeInfo.Children == null || rootTreeInfo.Children.Count == 0)
            {
                Point activityPosition = new Point(0, lastUsedYCoordinate);
                LogicalOperatorActivityBody bodyElement =
                    this.dictionary.GetActivityBody(this.conditionActivity.UniqueId, rootTreeInfo.CurrentModel);

                Canvas.SetTop(bodyElement, activityPosition.Y);
                Canvas.SetLeft(bodyElement, activityPosition.X);

                lastUsedYCoordinate += activityBodyHeight * 2;

            }
            else
            {
                double startYPos = lastUsedYCoordinate;

                foreach (WellFormedConditionalTreeInfo info in rootTreeInfo.Children)
                {
                    BuildWellFormedTreeOnCanvas(info, ref maxLevel, ref lastUsedYCoordinate);
                }
                double endYPosOfChild = lastUsedYCoordinate - activityBodyHeight;

                int requiredX = ((maxLevel - level)) * 2;
                Point position = new Point(requiredX * activityBodyWidth, (((endYPosOfChild - startYPos) / 2) - 20) + startYPos);
                LogicalOperatorActivityBody bodyElement =
                    this.dictionary.GetActivityBody(this.conditionActivity.UniqueId, rootTreeInfo.CurrentModel);

                Canvas.SetTop(bodyElement, position.Y);
                Canvas.SetLeft(bodyElement, position.X);
            }

            this.operatorCanvas.Height = lastUsedYCoordinate;
            if (this.operatorCanvas.Width < maxLevel * 2 * activityBodyWidth)
            {
                this.operatorCanvas.Width = maxLevel * 2 * activityBodyWidth;
            }

            Point logicalTreeExtremity = new Point(maxLevel * 2 * activityBodyWidth, lastUsedYCoordinate);
            this.RePositionOrphanElements(logicalTreeExtremity);
        }

        /// <summary>
        /// Reposition Orphan elements
        /// </summary>
        /// <param name="logicalTreeEndpoint">Point</param>
        private void RePositionOrphanElements(Point logicalTreeEndpoint)
        {
            Collection<SimpleActivityModel> activityModels = this.CheckForOrphanElements();
            if (activityModels.Count > 0)
            {
                // Dummy point for comparison.
                double minYPoint = 1000;
                double maxYPoint = 0;
                double maxYOfOrphan = 0;
                List<LogicalOperatorActivityBody> logicalUiElements = new List<LogicalOperatorActivityBody>();
                foreach (SimpleActivityModel activityModel in activityModels)
                {
                    if (this.dictionary != null)
                    {
                        LogicalOperatorActivityBody body = this.dictionary.GetActivityBody(this.conditionActivity.UniqueId, activityModel);
                        double yCoordinate = Canvas.GetTop(body) + body.Height;
                        double xCoordinate = Canvas.GetLeft(body);
                        if (yCoordinate < logicalTreeEndpoint.Y && xCoordinate < logicalTreeEndpoint.X)
                        {
                            if (yCoordinate < minYPoint)
                            {
                                minYPoint = yCoordinate;
                            }
                            logicalUiElements.Add(body);
                        }
                        if (yCoordinate > maxYOfOrphan)
                        {
                            maxYOfOrphan = yCoordinate;
                        }
                    }
                }

                foreach (LogicalOperatorActivityBody orphanWithinTree in logicalUiElements)
                {
                    double yCoordinate = Canvas.GetTop(orphanWithinTree);
                    double newYCoordinate = (yCoordinate - minYPoint) + logicalTreeEndpoint.Y;
                    Canvas.SetTop(orphanWithinTree, newYCoordinate);
                    if (maxYPoint < newYCoordinate)
                    {
                        maxYPoint = newYCoordinate;
                    }
                    double requiredHeight = maxYPoint + activityBodyHeight;
                    if (requiredHeight > maxYOfOrphan)
                    {
                        maxYOfOrphan = requiredHeight;
                    }
                }

                this.operatorCanvas.Height = maxYOfOrphan;
            }
        }

        /// <summary>
        /// Check if a well formed logical tree if formed from the root activity model given.
        /// </summary>
        /// <param name="lastBoundActivityModel">The root activity model.</param>
        /// <returns>True if the activity is a part of a well formed tree.</returns>
        private bool CheckIfWellFormedTree(SimpleActivityModel lastBoundActivityModel, WellFormedConditionalTreeInfo treeInfo, List<SimpleActivityModel> traversedModels, int level)
        {
            int childLevel = --level;

            // Add the activity model. Need to ignore if a loop is formed.
            traversedModels.Add(lastBoundActivityModel);

            // Iterate through the input paremeters of the model.
            foreach (ParameterDescriptionModel parameterModel in lastBoundActivityModel.InputParameters)
            {
                if (!parameterModel.IsDatabound)
                {
                    if (parameterModel.Value == null)
                    {
                        return false;
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    if (parameterModel.Value != null)
                    {
                        DatabindModel bind = parameterModel.Value as DatabindModel;
                        string sourceActivityName = bind.SourceActivityName;
                        SimpleActivityModel sourceModel = this.dictionary.GetActivityModel(this.conditionActivity.UniqueId, sourceActivityName);

                        if (sourceModel != null)
                        {
                            // Ignore Self binding.
                            if (traversedModels.Contains(sourceModel))
                            {
                                continue;
                            }

                            WellFormedConditionalTreeInfo childTreeInfo = this.CreateTreeInfo(sourceModel, treeInfo, childLevel);
                            if (CheckIfWellFormedTree(sourceModel, childTreeInfo, traversedModels, childLevel))
                            {
                                continue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// Create a wellformedtreeinfo from the activity model and add it to the parent.
        /// </summary>
        /// <param name="model">The activity model</param>
        /// <param name="parentInfo">The parent tree info.</param>
        private WellFormedConditionalTreeInfo CreateTreeInfo(SimpleActivityModel model, WellFormedConditionalTreeInfo parentInfo, int level)
        {
            // Create a new treeinfo object and add it to the parent.
            WellFormedConditionalTreeInfo childInfo = new WellFormedConditionalTreeInfo(this.conditionActivity.ParentModel.Name,
                    model, level);

            if (parentInfo != null)
            {
                parentInfo.AddChild(childInfo);
            }
            else
            {
                parentInfo = childInfo;
            }
            return childInfo;
        }

        /// <summary>
        /// Get the composer control instance.
        /// </summary>
        private void GetComposerControl()
        {
            string composerCtrlName = (string)this.GetValue(ComposerControl.ComposerControlNameProperty);
            this.composerCtrl = Application.Current.MainWindow.FindName(composerCtrlName) as ComposerControl;
        }

        #region ITridentUIElement Members

        public void ApplySelectedStyle()
        {
            throw new NotImplementedException();
        }

        public void ApplyUnselectedStyle()
        {
            throw new NotImplementedException();
        }

        public void CreateContextMenu()
        {
            throw new NotImplementedException();
        }

        public event EventHandler DeleteElement;

        public Point GetBindingEndpoint(UIElement relativeTo)
        {
            throw new NotImplementedException();
        }

        public Point GetBindingStartPoint(UIElement relativeTo)
        {
            throw new NotImplementedException();
        }

        public int FetchUIElementPosition()
        {
            throw new NotImplementedException();
        }

        public BaseModel Model
        {
            get { return this.conditionActivity; }
        }

        public event EventHandler SelectElement;

        public event EventHandler<ModelEventArgs> UpdateClick;

        public FrameworkElement LeftControlFlowConnectionElement
        {
            get { return null; }
        }

        public FrameworkElement RightControlFlowConnectionElement
        {
            get { return null; }
        }

        public event EventHandler<ProvenanceModeEventArgs> ProvenanceMenuClick;

        #endregion
    }
}